
interface IStateMachineDescription {
    [key: string]: Object | string
}

class State {

    constructor() {
    }

    onEnter(): void {

    }

    onEntryFrom(state: string | number): void {

    }

    onExit(): void {

    }

    onUpdate(): void {

    }
}

class StateMachine {
    static STATES: string = 'states'
    static STARTING_STATE: string = 'starting-state'

    public previousStateName: number
    public stateName: number = 0;
    private states: { [key: string]: State };

    [key: string]: any

    constructor(description: IStateMachineDescription) {
        const startingStateName: number = description[StateMachine.STARTING_STATE] as number
        this.states = description[StateMachine.STATES] as any;
        this.setState(startingStateName)
    }

    public getState(): State {
        return this.states[this.stateName]
    }

    public getAllStatesNames(): string[] {
        let keys = [];
        for (let key in this.states) {
            keys.push(key);
        }
        return keys
    }

    public setState(stateName: number): void {
        if (stateName == this.stateName) {
            return;
        }

        const currentState = this.getState()
        if (currentState) {
            currentState.onExit()
        }

        // Set the new state
        this.previousStateName = this.stateName
        this.stateName = stateName

        const state = this.getState()
        state.onEnter()
        state.onEntryFrom(this.previousStateName)
    }

    public onUpdate(): void {
        this.getState().onUpdate();
    }

    public onExit(): void {
        this.getState().onExit();
    }
}

export { StateMachine, State, IStateMachineDescription }
